#![no_std]
#![no_main]
extern crate alloc;

use alloc::boxed::Box;
use alloc::rc::Rc;
use core::cell::RefCell;
use core::fmt::Debug;
use display_interface_spi::SPIInterfaceNoCS;
use embassy_executor::Spawner;
use embassy_time::Timer;
use embedded_graphics::mono_font::iso_8859_7::FONT_5X8;
use embedded_graphics::mono_font::MonoTextStyle;
use embedded_graphics::text::Text;
use embedded_graphics_core::Drawable;
use embedded_graphics_core::pixelcolor::BinaryColor;
use embedded_graphics_core::prelude::{DrawTarget, Point};
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayMs;
use esp_hal::clock::{CpuClock, RadioClockController};
use esp_hal::delay::Delay;
use esp_hal::{main, spi, Blocking};
use esp_hal::gpio::{Level, Output, OutputConfig};
use esp_hal::i2c::master::I2c;
use esp_hal::peripherals::Peripherals;
use esp_hal::rtc_cntl::Rtc;
use esp_hal::spi::master::Config;
use esp_hal::spi::master::Spi;
use esp_hal::time::{Duration, Instant, Rate};
use esp_hal::timer::systimer::SystemTimer;
use esp_hal::timer::timg::TimerGroup;
use esp_println::logger::{init_logger, init_logger_from_env};
use log::{error, info, warn, LevelFilter};
use mipidsi::Display;
use slint::platform::{Platform, WindowAdapter};
use slint::platform::software_renderer::{LineBufferProvider, MinimalSoftwareWindow, Rgb565Pixel};
use slint::{invoke_from_event_loop, PhysicalSize, PlatformError, Weak};
use ssd1306::{I2CDisplayInterface, Ssd1306};
use ssd1306::mode::BufferedGraphicsMode;
use ssd1306::prelude::*;

slint::include_modules!();

#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
    loop {
        error!("panic:{}",info);
    }
}


// static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();

#[esp_hal_embassy::main]
async fn main(spawner: Spawner) -> ! {
    // generator version: 0.3.1
    // init_logger_from_env();
    init_logger(LevelFilter::Debug);
    esp_alloc::heap_allocator!(size: 100 * 1024);

    let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
    let peripherals =esp_hal::init(config);

    // 配置异步
    let timer0 = SystemTimer::new(peripherals.SYSTIMER);
    esp_hal_embassy::init(timer0.alarm0);


    let i2c = esp_hal::i2c::master::I2c::new(peripherals.I2C0, esp_hal::i2c::master::Config::default()
        .with_frequency(Rate::from_khz(400)))
        .unwrap()
        .with_sda(peripherals.GPIO8)
        .with_scl(peripherals.GPIO9);

    let display = Ssd1306::new(
        I2CDisplayInterface::new(i2c),
        DisplaySize128x64,
        DisplayRotation::Rotate0).into_buffered_graphics_mode();


    info!("分配内存完成");
    info!("开始渲染屏幕了");

    info!("开启异步任务");
    // spawner.spawn(ui_task(ui_weak)).ok();
    spawner.spawn(ui_run(display,spawner)).ok();


    loop{
        Timer::after_secs(2).await;
    }
    // for inspiration have a look at the examples at https://gitcahub.com/esp-rs/esp-hal/tree/esp-hal-v1.0.0-beta.0/examples/src/bin
}

#[embassy_executor::task]
async fn ui_run(mut display: SSD,spawner: Spawner){
    // 创建平台实例
    let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(
        slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,
    );
    window.set_size(PhysicalSize::new(128,64));
    let platform = EspPlatform::new(window.clone());
    slint::platform::set_platform(Box::new(platform)).unwrap();

    // 创建ui
    let ui = MainView::new().unwrap();
    ui.window().set_size(PhysicalSize::new(128,64));

    let ui_weak = ui.as_weak();
    spawner.spawn(ui_task(ui_weak)).ok();

    info!("进入了loop run");
    // 初始化显示
    display.init().unwrap();
    display.clear(BinaryColor::Off).unwrap();
    display.flush().unwrap();
    info!("清理屏幕 on");

    // 创建行缓冲区
    let display_width = 128; // 根据实际显示宽度设置
    let mut the_frame_buffer = [Rgb565Pixel(0); 128 * 64]; // 128x64
    loop {
        // 更新UI状态
        slint::platform::update_timers_and_animations();
        // info!("window has activie {}",window.has_active_animations());
        // 渲染UI
        window.draw_if_needed(|renderer| {
            // display.clear(BinaryColor::Off).unwrap();
            info!("进入渲染回调");
            // renderer.render_by_line(line_buffer);
            renderer.render_by_line(FrameBuffer{ frame_buffer: &mut the_frame_buffer, stride: display_width,display:&mut display });
            // info!("buf len {}",the_frame_buffer.len());
            info!("退出渲染回调");
            display.flush().unwrap();
        });
        Timer::after_millis(100).await;
    }
}

#[embassy_executor::task]
async fn ui_task(view:Weak<MainView>){
    info!("ui_task 已经开启");
    loop{
        let view = view.clone();
        /*invoke_from_event_loop(move || {
            let show = view.unwrap().global::<MyState>().get_is_show();
            info!("show的状态为：{}",show);
            view.unwrap().global::<MyState>().set_is_show(!show);
        }).unwrap();*/
        let view = view.upgrade().unwrap();
        let show = view.global::<MyState>().get_is_show();
        view.global::<MyState>().set_is_show(!show);
        info!("show的状态为：{}",show);
        Timer::after_secs(2).await;
    }

}

// 平台实现结构体
type SSD = Ssd1306<I2CInterface<I2c<'static,Blocking>>,DisplaySize128x64,BufferedGraphicsMode<DisplaySize128x64>>;
struct EspPlatform{
    window: Rc<slint::platform::software_renderer::MinimalSoftwareWindow>,
}

impl EspPlatform {
    fn new(window:Rc<MinimalSoftwareWindow>) -> Self {
        Self {
            window
        }
    }
}


/// 实现 Platform trait
impl Platform for EspPlatform {
    fn create_window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {
        info!("成功创建了window");
        Ok(self.window.clone())
    }

    fn duration_since_start(&self) -> core::time::Duration {
        // 使用定时器获取时间（需要实际硬件计时器实现）
        let time = Instant::now().duration_since_epoch().as_millis();
        // info!("time :{}",time);
        core::time::Duration::from_millis(
            time
        )
        // core::time::Duration::from_millis(unsafe { core::ptr::read_volatile(0x6000_0000 as *const u64) })
    }
}


struct FrameBuffer<'a>{ frame_buffer: &'a mut [Rgb565Pixel], stride: usize,display:&'a mut SSD }
impl<'a> LineBufferProvider for FrameBuffer<'a> {
    type TargetPixel = Rgb565Pixel;
    fn process_line(
        &mut self,
        line: usize,
        range: core::ops::Range<usize>,
        render_fn: impl FnOnce(&mut [Self::TargetPixel]),
    ) {
        let line_start = line * self.stride;
        let line_pixels = &mut self.frame_buffer[line_start..line_start + 128];
        // info!("process_line {}",line);

        render_fn(&mut line_pixels[range.clone()]);
        // warn!("设置后的：{:?}",line_pixels);

        // 规定蓝色为亮
        let t = Rgb565Pixel(31);
        let t2 = Rgb565Pixel(2175);
        let t3 = Rgb565Pixel(42270);
        let t4 = Rgb565Pixel(46495);
        let t5 = Rgb565Pixel(57055);
        let t6 = Rgb565Pixel(59166);
        let white = Rgb565Pixel(63391);
        let black = Rgb565Pixel(0);
        for (x,row) in line_pixels.iter().enumerate(){
            self.display.set_pixel(x as u32,line as u32,false);

            if row == &black{
                self.display.set_pixel(x as u32, line as u32, true);
            }
            /*if row == &t || row == &t2|| row == &t3|| row == &t4|| row == &t5|| row == &t6{
                self.display.set_pixel(x as u32, line as u32, true);
            }*/
            /*if row != &white{
                self.display.set_pixel(x as u32, line as u32, true);
            }*/
        }
    }
}

